---@module apiCache
-- 用于保存没有发送成功的api当网络再次通了的时候继续发送
-- 其他应用可以直接调用apiCache.http 方法进行api发送，调用该方法发送后如果发送失败将会保存下来，会在开机或者其他时候网络成功后继续发送出去

require "log"
require "tool"
module(..., package.seeall)
local MAX_ITEM = 10 -- 最多保留的api条数

local logPath = "/apiCache.log" --设备日志
local RETRY_MIN = 30 -- 重试间隔30分钟

local function init()
    if io.exists(logPath) == false then
        local empty = { item = {} }
        io.writeFile(logPath, json.encode(empty))
    end
end

init()


-- 将data保存到文件系统中
---@param logfile string
local function save(logfile)
    local jsondata = json.encode(logfile)
    io.writeFile(logPath, jsondata)
end


-- 用于智能提示
---@class ApiEntity
---@field url string "请求的url"
---@field bodystr string "发送的body"
---@field method string "调用方法一般为POST"


---@param apiEnt ApiEntity
local function addCache(apiEnt)
    log.info("add apiCache:")
    tool.print_dump(apiEnt)
    local str = io.readFile(logPath)
    local dat, res, _ = json.decode(str)
    if res then
        local num = #dat.item
        if num < MAX_ITEM then
            dat.item[num + 1] = apiEnt
        else
            -- 删除第一条
            table.remove(dat.item, 1)
            dat.item[MAX_ITEM] = apiEnt
        end
        save(dat)
    end
end

local function mycb(result, statusCode, head, body, logApi)
    log.info("apiCache-mycb", result, statusCode, body)
    if result == true then

    else
        -- 连接失败,加入到缓存中方便后续继续调用
        addCache(logApi)
    end

end


-- 其他应用可以直接调用apiCache.http 方法进行api发送，调用该方法发送后如果发送失败将会保存下来，会在开机或者其他时候网络成功后继续发送出去
function request(method, url, bodystr, timeout, cb)
    --http.request("POST", config.IOT_BOOT_URL, nil, {
    --    ["Content-Type"] = "application/json;charset=utf-8",
    --}, bodystr, 10000, bootstapcbfunc)
    ---@type ApiEntity
    local logApi = {}
    logApi.bodystr = bodystr
    logApi.method = method
    logApi.url = url
    logApi.retrynum = 0 --重试次数

    http.request(method, url, nil, {
        ["Content-Type"] = "application/json;charset=utf-8",
    }, bodystr, timeout, function(result, statusCode, head, body)
        if cb ~= nil then
            cb(result, statusCode, head, body)
        end
        mycb(result, statusCode, head, body, logApi)
    end)
end

---@param apiEnt ApiEntity
function apiRetry(apiEnt)
    log.info("apiRetry apiEnt=")
    tool.print_dump(apiEnt)
    http.request(apiEnt.method, apiEnt.url, nil, {
        ["Content-Type"] = "application/json;charset=utf-8",
    }, apiEnt.bodystr, 10000, function(result, statusCode, head, body)
        log.info("apiRetry cb", result, statusCode, body)
        if result == true then
            -- 有返回
            sys.publish("apiCache_retry", "ok")
            return
        else

        end
    end)
end

function startRetryTask()
    sys.taskInit(function()
        while true do
            --sys.wait(60000*60) -- 1小时一次
            sys.wait(60000 * RETRY_MIN) -- 1小时一次
            --sys.wait(300000)
            local logStr = io.readFile(logPath)
            local dat, res, _ = json.decode(logStr)
            if res and net.getNetMode() ~= 0 then
                log.info("apiCache", "api cache nums=" .. #dat.item)
                if #dat.item > 0 then
                    ---@type ApiEntity
                    local apiEn = {}
                    -- 为了避免删除导致的下标变动，复制一个
                    local itemListCopy = tool.deepCopy(dat.item)
                    -- 将重试次数retrynum大于3的，还有-1的重新成功的去掉
                    dat.item = {}
                    for i = 1, #itemListCopy do
                        apiEn = itemListCopy[i]
                        if apiEn.retrynum == nil then
                            apiEn.retrynum = 1
                        end
                        --同步日志
                        apiRetry(apiEn)
                        local result, data = sys.waitUntil("apiCache_retry", 15000)
                        if result and data == "ok" then
                            apiEn.retrynum = -1 --标记为已经完成发送了
                        else
                            -- 还是发送不出去，可能是网络问题,先退出
                            log.info("apiCache", "cant retry maybe network not ok", "--retyrnum=", apiEn.retrynum)
                            apiEn.retrynum = apiEn.retrynum + 1
                            -- 保存用于下次发送-- 如果进行了3次重试都不行就删掉了
                            if apiEn.retrynum < 24 and apiEn.retrynum > 0 then
                                table.insert(dat.item, apiEn)
                            end
                        end
                    end
                    save(dat)
                end


            end
            logStr, dat = nil, nil
            collectgarbage("collect")
        end
    end)
end

-- 测试启动
function startRetryTaskTest()
    RETRY_MIN = 1 -- 1分钟

    ---@type ApiEntity
    local logApi1 = {}
    logApi1.bodystr = "AAAAAAAAAAAAA"
    logApi1.method = "POST"
    logApi1.url = "https://www.baidu.com/aa/cc"
    logApi1.retrynum = 0 --重试次数


    local logApi2 = {}
    logApi2.bodystr = "AAAAAAAAAAAAA"
    logApi2.method = "POST"
    logApi2.url = "https://www.22211.com/aa/bb"
    logApi2.retrynum = 0 --重试次数


    addCache(logApi1)
    addCache(logApi2)

    startRetryTask()
end